package com.bilibili.dubbo.api;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.bilibili.dubbo.api.mongo.MovementApi;
import com.bilibili.dubbo.async.TimeLineService;
import com.bilibili.dubbo.utils.IdWorker;
import com.bilibili.model.mongo.Movement;
import com.bilibili.model.mongo.MovementTimeLine;
import com.bilibili.model.mongo.Visitors;
import com.bilibili.model.vo.PageResult;
import org.apache.commons.lang3.RandomUtils;
import org.apache.dubbo.config.annotation.DubboService;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author HuangRongFu
 * 2021/11/21 星期日5:18 下午
 */

@DubboService
public class MovementApiImpl implements MovementApi {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private TimeLineService timeLineService;

    /**
     * 发布动态
     *
     * @param: movement
     * @Return: void
     */
    @Override
    public void publish(Movement pojo) {
        //movement 中还有两个数据需要补全 pid  和 发布时间
        pojo.setPid(idWorker.getNextId("movement"));

        //发布时间补全
        long currentTimeMillis = System.currentTimeMillis();
        pojo.setCreated(currentTimeMillis);

        //数据补全后就可以发布动态了
        //后续的操作是这条动发布后 好友应该能看见 所以要去查询好友表  对时间表操作
        mongoTemplate.insert(pojo);

        //异步操作
        timeLineService.saveTimeLine(pojo.getUserId(), pojo.getId(), currentTimeMillis);
        //要去通过用户id查询用户好友集合
        /*
        Query friendQuery = new Query(Criteria.where("userId").is(pojo.getUserId()));

        List<Friend> friendList = mongoTemplate.find(friendQuery, Friend.class);

        //判断好友集合是否为空 不为空就取出好友id集合
        //在好友列表人数不多是 可以一个一个取后添加 数据量大时 采用异步处理 或者批量添加
        if (CollectionUtil.isNotEmpty(friendList)){

            //添加到时间线表中
            for (Friend friend : friendList) {

                MovementTimeLine timeLine = new MovementTimeLine();
                timeLine.setFriendId(pojo.getUserId());
                timeLine.setUserId(friend.getFriendId());
                timeLine.setCreated(currentTimeMillis);
                timeLine.setMovementId(pojo.getId());//设置动态id

                mongoTemplate.insert(timeLine);
            }
        } */
    }

    /**
     * 用户动态  只是查询个人的
     *
     * @param: page
     * @param: pageSize
     * @param: userId
     * @Return: PageResult
     */
    @Override
    public PageResult findByUserId(Long page, Long pageSize, Long userId) {

        //构建查询的条件
        Query query = new Query(Criteria.where("userId").is(userId));

        //获取总数
        long total = mongoTemplate.count(query, Movement.class);

        //计算分页的起始行号
        long start = (page - 1) * pageSize;

        List<Movement> movementList = new ArrayList<>();
        //如果过total>page 就一页 就不用分页
        if (total > start) {

            query.skip(start).limit(pageSize.intValue());
            query.with(Sort.by(Sort.Order.desc("created")));
            movementList = mongoTemplate.find(query, Movement.class);

        }

        return new PageResult(page, pageSize, total, movementList);
    }

    /**
     * 好友动态
     *
     * @param: page
     * @param: pageSize
     * @param: userId
     * @Return: List<Movement>
     */
    @Override
    public PageResult findFriendMovement(Long page, Long pageSize, Long userId) {

        //构建查询条件
        Query query = new Query(Criteria.where("friendId").is(userId));

        //查询总记录数
        long total = mongoTemplate.count(query, MovementTimeLine.class);

        //设置起始行
        Long start = (page - 1) * pageSize;

        List<Movement> movementList = new ArrayList<>();
        //满足条件就需要分页
        if (total > start) {

            query.skip(start).limit(pageSize.intValue());
            query.with(Sort.by(Sort.Order.desc("created")));

            List<MovementTimeLine> timeLineList = mongoTemplate.find(query, MovementTimeLine.class);

            //获取动态id集合
            List<ObjectId> movementIds = timeLineList.stream()
                    .map(MovementTimeLine::getMovementId).collect(Collectors.toList());

            Query movementQuery = new Query(Criteria.where("_id").in(movementIds));

            movementQuery.with(Sort.by(Sort.Order.desc("created")));

            movementList = mongoTemplate.find(movementQuery, Movement.class);
        }

        return new PageResult(page, pageSize, total, movementList);
    }

    /**
     * 随机推荐十条动态
     *
     * @Return: List
     */
    @Override
    public List<Movement> RandomMovement() {

        Query query = new Query();

        //查询动态表中有多少条记录
        long total = mongoTemplate.count(query, Movement.class);

        //记录没有十条  直接全部返回
        if (total < 10) {

            return mongoTemplate.find(query, Movement.class);
        } else {
            //记录大于十条
            long start = RandomUtils.nextLong(0, total - 9);

            query.skip(start).limit(10);

            return mongoTemplate.find(query, Movement.class);
        }
    }

    /**
     * 通过pid查询动态信息
     *
     * @return
     * @param: pidList
     */
    @Override
    public List<Movement> findByPids(List<Long> pidList) {

        Query query = new Query(Criteria.where("pid").in(pidList));

        return mongoTemplate.find(query, Movement.class);
    }

    /**
     * 查询单条动态
     *
     * @param: movementId
     * @Return: Movement
     */
    @Override
    public Movement findMovementById(String movementId) {
        return mongoTemplate.findById(new ObjectId(movementId), Movement.class);
    }

    /**
     * 谁看过我
     *
     * @param userId
     * @Return: List
     */
    @Override
    public List<Visitors> queryVisitorsList(Long userId, Long date) {

        Query query = new Query(Criteria.where("userId").is(userId));

        if (date != null) {

            query.addCriteria(Criteria.where("date").gt(date));
        }

        query.limit(5).with(Sort.by(Sort.Order.desc("date")));

        return mongoTemplate.find(query, Visitors.class);

    }

    /**
     * 更新动态审核状态
     * @param movementId
     * @param state
     * @Return: void
     */
    @Override
    public void update(String movementId, Integer state) {

        Query query = Query.query(Criteria.where("id").in(new ObjectId(movementId)));
        Update update = Update.update("state", state);
        mongoTemplate.updateFirst(query, update, Movement.class);
    }
}
